package com.hahaliu.hahaliu.service.impl.video;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hahaliu.hahaliu.common.constant.VideoConstant;
import com.hahaliu.hahaliu.common.context.CurrentUser;
import com.hahaliu.hahaliu.common.exception.BaseException;
import com.hahaliu.hahaliu.common.utils.MinioUtil;
import com.hahaliu.hahaliu.common.utils.RedisUtil;
import com.hahaliu.hahaliu.mapper.CategoryMapper;
import com.hahaliu.hahaliu.mapper.FavoriteVideoMapper;
import com.hahaliu.hahaliu.mapper.UserMapper;
import com.hahaliu.hahaliu.mapper.VideoMapper;
import com.hahaliu.hahaliu.pojo.dto.UserDTO;
import com.hahaliu.hahaliu.pojo.entity.Category;
import com.hahaliu.hahaliu.pojo.entity.User;
import com.hahaliu.hahaliu.pojo.entity.Video;
import com.hahaliu.hahaliu.pojo.vo.VideoInfoVO;
import com.hahaliu.hahaliu.service.category.CategoryService;
import com.hahaliu.hahaliu.service.user.UserService;
import com.hahaliu.hahaliu.service.video.VideoService;
import com.hahaliu.hahaliu.service.video.VideoStatsService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @author Liubuzhu
* @description 针对表【video】的数据库操作Service实现
* @createDate 2024-05-18 14:50:03
*/
@Service
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video>
    implements VideoService{

	@Autowired
	private VideoMapper videoMapper;

	@Autowired
	private VideoStatsService videoStatsService;

	@Autowired
	private UserMapper userMapper;

	@Autowired
	private CategoryService categoryService;

	@Autowired
	private CategoryMapper categoryMapper;
	
	@Autowired
	private FavoriteVideoMapper favoriteVideoMapper;

	@Autowired
	private IService<Video> videoService;

	@Autowired
	private CurrentUser currentUser;

	@Autowired
	private RedisUtil redisUtil;

	@Autowired
	private UserService userService;

	@Autowired
	private MinioUtil minioUtil;

	@Autowired
	private SqlSessionFactory sqlSessionFactory;

	@Autowired
	@Qualifier("taskExecutor")
	private Executor taskExecutor;

	@Override
	public List<VideoInfoVO> listWithUser() {
		List<VideoInfoVO> videoInfoList = new ArrayList<>();


		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
		// 查询已审核的video
		queryWrapper.eq("status", 1)
				.last("order by rand() limit 11"); // 添加随机排序和限制数量条件
		List<Video> videoList = videoMapper.selectList(queryWrapper);
		// 遍历video对象列表
		for (Video video : videoList) {
			int uId = video.getUId();

			// 使用QueryWrapper构建查询条件
			QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
			queryWrapper2.eq("u_id", uId);

			// 根据video对象中的uId字段查询user对象
			User user = userMapper.selectOne(queryWrapper2);

			QueryWrapper<Category> queryWrapper3 = new QueryWrapper<>();
			queryWrapper3.eq("mc_id", video.getMcId());
			Category category = categoryMapper.selectOne(queryWrapper3);


			// 创建VideoInfoVO对象，将user对象和video对象封装进去
			VideoInfoVO videoInfo = new VideoInfoVO();
			UserDTO userDTO = new UserDTO();
			BeanUtils.copyProperties(user, userDTO);
			videoInfo.setUser(userDTO);
			videoInfo.setVideo(video);
			videoInfo.setCategory(category);

			// 将VideoInfoVO对象添加到列表中
			videoInfoList.add(videoInfo);
		}
		return videoInfoList;
	}

	@Override
	public VideoInfoVO getInfo(Integer vId) {

		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("v_id", vId);
		Video video = videoMapper.selectOne(queryWrapper);
		if (video == null) {
			throw new BaseException("视频怎么不见啦~");
		}

		// 使用QueryWrapper构建查询条件
		QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
		queryWrapper2.eq("u_id", video.getUId());

		// 根据video对象中的uId字段查询user对象
		User user = userMapper.selectOne(queryWrapper2);
		// 将VideoInfo对象转换为VideoInfoVO对象
		VideoInfoVO videoInfoVO = new VideoInfoVO();
		UserDTO userDTO = new UserDTO();
		BeanUtils.copyProperties(user, userDTO);
		videoInfoVO.setUser(userDTO);
		videoInfoVO.setVideo(video);

		QueryWrapper<Category> queryWrapper3 = new QueryWrapper<>();
		queryWrapper3.eq("mc_id", video.getMcId());
		Category category = categoryMapper.selectOne(queryWrapper3);
		videoInfoVO.setCategory(category);

		return videoInfoVO;
	}

	@Override
	public IPage<VideoInfoVO> searchByNameLike(String name, Integer page, Integer quantity) {
		Page<Video> pageInfo = new Page<>(page, quantity);

		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
		queryWrapper.like("title", name);
		// 查询已过审的视频
		queryWrapper.eq("status", VideoConstant.HAS_PASSED);
		Page<Video> videoPage = videoMapper.selectPage(pageInfo, queryWrapper);

		List<VideoInfoVO> videoInfoList = new ArrayList<>();

		List<Video> videoList = videoPage.getRecords();

		for (Video video : videoList) {
			QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
			queryWrapper2.eq("u_id", video.getUId());

			User user = userMapper.selectOne(queryWrapper2);
			// 将VideoInfo对象转换为VideoInfoVO对象
			VideoInfoVO videoInfoVO = new VideoInfoVO();
			UserDTO userDTO = new UserDTO();
			BeanUtils.copyProperties(user, userDTO);
			videoInfoVO.setUser(userDTO);
			videoInfoVO.setVideo(video);
			videoInfoList.add(videoInfoVO);
		}

		// 将查询结果封装到新的 IPage 对象中，保留原有的分页信息
		IPage<VideoInfoVO> videoInfoVOPage = new Page<>(page, quantity);
		videoInfoVOPage.setRecords(videoInfoList);
		videoInfoVOPage.setTotal(videoPage.getTotal());
		videoInfoVOPage.setSize(videoPage.getSize());
		videoInfoVOPage.setCurrent(videoPage.getCurrent());

		return videoInfoVOPage;
	}

	public List<VideoInfoVO> getRecommend() {
		List<VideoInfoVO> videoInfoList = new ArrayList<>();

		// 查询已审核的video对象
		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("status", 1) // 设置status为1的条件
				.last("order by rand() limit 10"); // 添加随机排序和限制数量条件
		List<Video> videoList = videoMapper.selectList(queryWrapper);
		// 遍历video对象列表
		for (Video video : videoList) {
			int uId = video.getUId();

			// 使用QueryWrapper构建查询条件
			QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
			queryWrapper2.eq("u_id", uId);

			// 根据video对象中的uId字段查询user对象
			User user = userMapper.selectOne(queryWrapper2);

			// 创建VideoInfoVO对象，将user对象和video对象封装进去
			VideoInfoVO videoInfo = new VideoInfoVO();
			UserDTO userDTO = new UserDTO();
			BeanUtils.copyProperties(user, userDTO);
			videoInfo.setUser(userDTO);
			videoInfo.setVideo(video);

			// 将VideoInfoVO对象添加到列表中
			videoInfoList.add(videoInfo);
		}
		return videoInfoList;
	}

	@Override
	public List<Integer> getVIds() {
		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("status", 1);
		queryWrapper.select("v_id");

		return videoMapper.selectList(queryWrapper).stream().map(Video::getVId).collect(Collectors.toList());
	}

	public IPage<VideoInfoVO> selectUserPage(Integer status, Integer page, Integer quantity) {

		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("status", status);

		// 创建分页对象
		Page<Video> pageInfo = new Page<>(page, quantity);
		Page<Video> videoPage = videoMapper.selectPage(pageInfo, queryWrapper);

		List<Video> videoList = videoPage.getRecords();

		List<VideoInfoVO> videoInfoVOList = new ArrayList<>();
		for (Video video : videoList) {
			User user = userMapper.selectById(video.getUId());
			Category category = categoryMapper.selectById(video.getMcId());
			VideoInfoVO videoInfo = new VideoInfoVO();
			UserDTO userDTO = new UserDTO();
			BeanUtils.copyProperties(user, userDTO);
			videoInfo.setUser(userDTO);
            videoInfo.setVideo(video);
            videoInfo.setCategory(category);
			videoInfoVOList.add(videoInfo);
		}

		// 将查询结果封装到新的 IPage 对象中，保留原有的分页信息
		IPage<VideoInfoVO> videoInfoVOPage = new Page<>(page, quantity);
		videoInfoVOPage.setRecords(videoInfoVOList);
		videoInfoVOPage.setTotal(videoPage.getTotal());
		videoInfoVOPage.setSize(videoPage.getSize());
//		videoInfoVOPage.setCurrent(videoPage.getCurrent());

		return videoInfoVOPage;
	}

	/**
	 * 更新视频状态，包括过审、不通过、删除，其中审核相关需要管理员权限，删除可以是管理员或者投稿用户
	 * @param vid   视频ID
	 * @param status 要修改的状态，1通过 2不通过 3删除
	 * @return 无data返回，仅返回响应信息
	 */
	public void updateVideoStatus(Integer vid, Integer status) {
		Integer userId = currentUser.getUserId();
		if (status == 1 || status == 2) {
			if (!currentUser.isAdmin()) {
				throw new BaseException("您不是管理员，无权访问");
			}
			if (status == 1) {
				QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
				queryWrapper.eq("v_id", vid).ne("status", 3);
				Video video = videoMapper.selectOne(queryWrapper);
				if (video == null) {
					throw new BaseException("视频不见了QAQ");
				}
				Integer lastStatus = video.getStatus();
				video.setStatus(1);
				UpdateWrapper<Video> updateWrapper = new UpdateWrapper<>();
				updateWrapper.eq("v_id", vid).set("status", 1).set("upload_date", new Date());// 更新视频状态审核通过
				int flag = videoMapper.update(null, updateWrapper);
				if (flag > 0) {
					// 更新成功
//					esUtil.updateVideo(video);// 更新ES视频文档
					redisUtil.delMember("video_status:" + lastStatus, vid);// 从旧状态移除
					redisUtil.addMember("video_status:1", vid);// 加入新状态
					redisUtil.zset("user_video_upload:" + video.getUId(), video.getVId());
					redisUtil.delValue("video:" + vid);// 删除旧的视频信息
				} else {
					// 更新失败，处理错误情况
					throw new BaseException("更新状态失败");
				}
			}
			else {
				// 目前逻辑跟上面一样的，但是可能以后要做一些如 记录不通过原因 等操作，所以就分开写了
				QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
				queryWrapper.eq("v_id", vid).ne("status", 3);
				Video video = videoMapper.selectOne(queryWrapper);
				if (video == null) {
					throw new BaseException("视频不见了QAQ");
				}
				Integer lastStatus = video.getStatus();
				video.setStatus(2);
				UpdateWrapper<Video> updateWrapper = new UpdateWrapper<>();
				updateWrapper.eq("v_id", vid).set("status", 2);// 更新视频状态审核不通过
				int flag = videoMapper.update(null, updateWrapper);
				if (flag > 0) {
					// 更新成功
//					esUtil.updateVideo(video);  // 更新ES视频文档
					redisUtil.delMember("video_status:" + lastStatus, vid);// 从旧状态移除
					redisUtil.addMember("video_status:2", vid);// 加入新状态
					redisUtil.zsetDelMember("user_video_upload:" + video.getUId(), video.getVId());
					redisUtil.delValue("video:" + vid);// 删除旧的视频信息
				} else {
					// 更新失败，处理错误情况
					throw new BaseException("更新状态失败");
				}
			}
		} else if (status == 3) {
			QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("v_id", vid).ne("status", 3);
			Video video = videoMapper.selectOne(queryWrapper);
			if (video == null) {
				throw new BaseException("视频不见了QAQ");
			}
			if (Objects.equals(userId, video.getUId()) || currentUser.isAdmin()) {
				String videoUrl = video.getVideoUrl();
				String videoPrefix = videoUrl.split("http://127.0.0.1:9000/haha-billbill")[1];  // minio视频文件名
				String coverUrl = video.getCoverUrl();
				String coverPrefix = coverUrl.split("http://127.0.0.1:9000/haha-billbill")[1];  // minio封面文件名
				Integer lastStatus = video.getStatus();
				UpdateWrapper<Video> updateWrapper = new UpdateWrapper<>();
				updateWrapper.eq("vid", vid).set("status", 3).set("delete_date", new Date());     // 更新视频状态已删除
				int flag = videoMapper.update(null, updateWrapper);
				if (flag > 0) {
					// 更新成功
//					esUtil.deleteVideo(vid);
					redisUtil.delMember("video_status:" + lastStatus, vid);// 从旧状态移除
					redisUtil.delValue("video:" + vid);// 删除旧的视频信息
					redisUtil.delValue("danmu_idset:" + vid);// 删除该视频的弹幕
					redisUtil.zsetDelMember("user_video_upload:" + video.getUId(), video.getVId());
					// 搞个异步线程去删除minio的源文件
//					CompletableFuture.runAsync(() -> minioUtil.deleteFiles(videoPrefix), taskExecutor);
//					CompletableFuture.runAsync(() -> minioUtil.deleteFiles(coverPrefix), taskExecutor);
					// 批量删除该视频下的全部评论缓存
					CompletableFuture.runAsync(() -> {
						Set<Object> set = redisUtil.zReverange("comment_video:" + vid, 0, -1);
						List<String> list = new ArrayList<>();
						set.forEach(id -> list.add("comment_reply:" + id));
						list.add("comment_video:" + vid);
						redisUtil.delValues(list);
					}, taskExecutor);
				} else {
					// 更新失败，处理错误情况
					throw new BaseException("更新状态失败");
				}
			} else {
				throw new BaseException("您没有权限删除视频");
			}
		}
	}

	// TODO: 2024/6/15 这个方法有点问题，需要修改, 会有收藏夹为空的情况，这里没有处理，而且还要返回每个视频的收藏时间  2025/2/21 修改了
	public List<Map<String, Object>> getVideosWithDataByIdsOrderByDesc(List<Integer> idList, @Nullable String column, Integer page, Integer quantity) {
		// 使用事务批量操作 减少连接sql的开销
		try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
			List<Map<String, Object>> result;
			if (column == null) {
				// 如果没有指定排序列，就按idList排序
				QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
				queryWrapper.in("v_id", idList);
				List<Video> videos = videoMapper.selectList(queryWrapper);
				if (videos.isEmpty()) {
					sqlSession.commit();
					return Collections.emptyList();
				}
				result = idList.stream().parallel().flatMap(vid -> {
					Map<String, Object> map = new HashMap<>();
					// 找到videos中为vid的视频
					Video video = videos.stream()
							.filter(v -> Objects.equals(v.getVId(), vid))
							.findFirst()
							.orElse(null);
					if (video == null) return Stream.empty(); // 跳过该项
					if (video.getStatus() == 3) {
						// 视频已删除
						Video video1 = new Video();
						video1.setVId(video.getVId());
						video1.setUId(video.getUId());
						video1.setStatus(video.getStatus());
						video1.setDeleteDate(video.getDeleteDate());
						map.put("video", video1);
						return Stream.of(map);
					}
					map.put("video", video);
					CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
						map.put("user", userService.getUserById(video.getUId()));
						map.put("stats", videoStatsService.getVideoStatsById(video.getVId()));
					}, taskExecutor);
					CompletableFuture<Void> categoryFuture = CompletableFuture.runAsync(() -> {
						map.put("category", categoryService.getCategoryById(video.getMcId(), video.getScId()));
					}, taskExecutor);
					userFuture.join();
					categoryFuture.join();
					return Stream.of(map);
				}).collect(Collectors.toList());
			} else if (Objects.equals(column, "upload_date")) {
				// 如果按投稿日期排序，就先查video表
				QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
				queryWrapper.in("v_id", idList).orderByDesc(column).last("LIMIT " + quantity + " OFFSET " + (page - 1) * quantity);
				List<Video> list = videoMapper.selectList(queryWrapper);
				if (list.isEmpty()) {
					sqlSession.commit();
					return Collections.emptyList();
				}
				result = list.stream().parallel().map(video -> {
					Map<String, Object> map = new HashMap<>();
					if (video.getStatus() == 3) {
						// 视频已删除
						Video video1 = new Video();
						video1.setVId(video.getVId());
						video1.setUId(video.getUId());
						video1.setStatus(video.getStatus());
						video1.setDeleteDate(video.getDeleteDate());
						map.put("video", video1);
						return map;
					}
					map.put("video", video);
					CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
						map.put("user", userService.getUserById(video.getUId()));
						map.put("stats", videoStatsService.getVideoStatsById(video.getVId()));
					}, taskExecutor);
					CompletableFuture<Void> categoryFuture = CompletableFuture.runAsync(() -> {
						map.put("category", categoryService.getCategoryById(video.getMcId(), video.getScId()));
					}, taskExecutor);
					userFuture.join();
					categoryFuture.join();
					return map;
				}).collect(Collectors.toList());
			} else {
				// 否则按视频数据排序，就先查数据
				QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
				queryWrapper.in("v_id", idList).orderByDesc(column).last("LIMIT " + quantity + " OFFSET " + (page - 1) * quantity);
				List<Video> list = videoMapper.selectList(queryWrapper);
				if (list.isEmpty()) {
					sqlSession.commit();
					return Collections.emptyList();
				}
				result = list.stream().parallel().map(videoStats -> {
					Map<String, Object> map = new HashMap<>();
					Video video = videoMapper.selectById(videoStats.getVId());
					if (video.getStatus() == 3) {
						// 视频已删除
						Video video1 = new Video();
						video1.setVId(video.getVId());
						video1.setUId(video.getUId());
						video1.setStatus(video.getStatus());
						video1.setDeleteDate(video.getDeleteDate());
						map.put("video", video1);
						return map;
					}
					map.put("video", video);
					map.put("stats", videoStats);
					CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
						map.put("user", userService.getUserById(video.getUId()));
					}, taskExecutor);
					CompletableFuture<Void> categoryFuture = CompletableFuture.runAsync(() -> {
						map.put("category", categoryService.getCategoryById(video.getMcId(), video.getScId()));
					}, taskExecutor);
					userFuture.join();
					categoryFuture.join();
					return map;
				}).collect(Collectors.toList());
			}
			sqlSession.commit();
			return result;
		}
	}

	public Long getWorksCount(Integer uid) {
		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("u_id", uid);
        return videoMapper.selectCount(queryWrapper);
	}

	/**
	 * 根据vid查询单个视频信息，包含用户信息和分区信息
	 * @param vid 视频ID
	 * @return 包含用户信息、分区信息、视频信息的map
	 */
	@Override
	public VideoInfoVO getVideoWithDataById(Integer vid) {
		VideoInfoVO videoInfoVO = new VideoInfoVO();
		// 先查询 redis
		Video video = redisUtil.getObject("video:" + vid, Video.class);
		if (video == null) {
			// redis 查不到再查数据库
			QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("v_id", vid).ne("status", 3);
			video = videoMapper.selectOne(queryWrapper);
			if (video != null) {
				Video finalVideo1 = video;
				CompletableFuture.runAsync(() -> {
					redisUtil.setExObjectValue("video:" + vid, finalVideo1);    // 异步更新到redis
				}, taskExecutor);
			} else {
				return null;
			}
		}

		// 多线程异步并行查询用户信息和分区信息并封装
		Video finalVideo = video;
		CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
			videoInfoVO.setUser(userService.getUserById(finalVideo.getUId()));
			videoInfoVO.setVideo(videoStatsService.getVideoStatsById(finalVideo.getVId()));
		}, taskExecutor);
		CompletableFuture<Void> categoryFuture = CompletableFuture.runAsync(() -> {
			videoInfoVO.setCategory(categoryService.getCategoryById(finalVideo.getMcId(), finalVideo.getScId()));
		}, taskExecutor);
		videoInfoVO.setVideo(video);
		// 使用join()等待userFuture和categoryFuture任务完成
		userFuture.join();
		categoryFuture.join();

		return videoInfoVO;
	}

	/**
	 * 根据id分页获取视频信息，包括用户和分区信息
	 * @param set   要查询的视频id集合
	 * @param index 分页页码 为空默认是1
	 * @param quantity  每一页查询的数量 为空默认是10
	 * @return  包含用户信息、分区信息、视频信息的map列表
	 */
	@Override
	public List<Map<String, Object>> getVideosWithDataByIds(Set<Object> set, Integer index, Integer quantity) {
		if (index == null) {
			index = 1;
		}
		if (quantity == null) {
			quantity = 10;
		}
		int startIndex = (index - 1) * quantity;
		int endIndex = startIndex + quantity;
		// 检查数据是否足够满足分页查询
		if (startIndex > set.size()) {
			// 如果数据不足以填充当前分页，返回空列表
			return Collections.emptyList();
		}
		List<Video> videoList = new CopyOnWriteArrayList<>();   // 使用线程安全的集合类 CopyOnWriteArrayList 保证多线程处理共享List不会出现并发问题

		// 直接数据库分页查询
		List<Object> idList = new ArrayList<>(set);
		endIndex = Math.min(endIndex, idList.size());
		List<Object> sublist = idList.subList(startIndex, endIndex);

		// 如果 sublist 为空，直接返回空列表
		if (sublist.isEmpty()) {
			return Collections.emptyList();
		}

		QueryWrapper<Video> queryWrapper = new QueryWrapper<>();
		queryWrapper.in("v_id", sublist).ne("status", 3);
		videoList = videoMapper.selectList(queryWrapper);
		if (videoList.isEmpty()) return Collections.emptyList();

		// 并行处理每一个视频，提高效率
		// 先将videoList转换为Stream
		Stream<Video> videoStream = videoList.stream();
		List<Map<String, Object>> mapList = videoStream.parallel() // 利用parallel()并行处理
				.map(video -> {
					Map<String, Object> map = new HashMap<>();
					map.put("video", video);

					CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
						map.put("user", userService.getUserById(video.getUId()));
						map.put("stats", videoStatsService.getVideoStatsById(video.getVId()));
					}, taskExecutor);

					CompletableFuture<Void> categoryFuture = CompletableFuture.runAsync(() -> {
						map.put("category", categoryService.getCategoryById(video.getMcId(), video.getScId()));
					}, taskExecutor);

					// 使用join()等待全部任务完成
					userFuture.join();
					categoryFuture.join();
					return map;
				})
				.collect(Collectors.toList());
		return mapList;
	}
}




